function [risk, ror, weights] = portrand(asset, ret, pts, method)
%PORTRAND Randomized portfolio risks, returns, and weights.
%	Generate randomized portfolio risks, returns, and weights and, if no output arguments, plot the
%	mean versus the variance of portfolio returns for randomized portfolios.
%
%		portrand(ASSET, RET, PTS, METHOD);
%		[RISK, ROR, WEIGHTS] = portrand(ASSET, RET, PTS, METHOD);
%
%	Inputs:
%		ASSET - An M x N matrix where each column represents time series (asset return) data for a
%			single security.
%
%	Optional Inputs:
%		RET - A 1 x N vector where each column represents the rate of return for a corresponding
%			security in ASSET. The default for RET is the average value of each column of ASSET.
%		PTS - A scalar value that specifies how many random points to be generated. The default for
%			PTS is 1000.
%		METHOD - A string that specifies how to generate random portfolios from the set of
%			portfolios with two possible methods.
%			'UNIFORM'    Uniformly-distributed portfolio weights (default method).
%			'GEOMETRIC'  Concentrated portfolio weights around the geometric center of the set of
%						 portfolios.
%			It is sufficient to specify the letters 'u' or 'g' to select a method.
%
%	Outputs:
%		RISK - A PTS x 1 vector of standard deviations of each randomized portfolio.
%		ROR - A PTS x 1 vector of expected rates of return of each randomized portfolio.
%		WEIGHTS - A PTS x N matrix of asset weights.  Each row of WEIGHTS is a distinct portfolio.
%
%	Notes:
%		1) Portfolios are selected at random from a set of portfolios such that portfolio weights are
%			non-negative and sum to 1. The sample mean and covariance of asset returns are used to
%			compute portfolio returns for each random portfolio.
%		2) The 'UNIFORM' method generates portfolio weights that are uniformly-distributed on the
%			set of portfolio weights.
%			The 'GEOMETRIC' method generates portfolio weights that are concentrated around the
%			geometric center of the set of portfolio weights.
%		3) Both methods generate weights that are distributed symmetrically around the geometric
%			center of the set of weights.
%		4) This function is used in the MATLAB Financial Expo and illustrates how multiple weighting
%			combinations of the same portfolio can generate the same expected rate of return (which
%			is the use for the input argument RET).
%
%   Reference: Bodie, Kane, and Marcus, Investments, Chapter 7.
%
%   See also FRONTCON, PORTVAR, PORTROR.
%

%	Copyright 1995-2008 The MathWorks, Inc.
% 	$Revision: 1.7.2.7 $   $Date: 2008/05/12 21:25:12 $
 
if nargin < 1
	error('finance:portrand:missingInputs', ...
		'Missing required input argument: ASSET.');
end
if nargin < 2 || isempty(ret)
	ret = mean(asset);
end
if nargin < 3 || isempty(pts)
	pts = 1000;
end
if nargin < 4 || isempty(method)
	method = 'u';
end

[r, c] = size(asset);
[m, n] = size(ret);
if c ~= n
	error('finance:portrand:mismatchAssetRetSize', ...
		'ASSET and RET must have equal number of columns.');
end
if m ~= 1
	error('finance:portrand:invalidRetSize', ...
		'RET must be a 1x%1.0f vector.',c);
end
if length(pts) ~= 1 || pts < 1
	error('finance:portrand:invalidPts', ...
		'PTS must be a scalar value > 0.');
end
if ~ischar(method)
	error('finance:portrand:invalidMethod', ...
		'METHOD must be a string.');
end

% Generate random asset weight combinations

if lower(method(1)) == 'g'
	ws = rand(c, pts);
elseif lower(method(1)) == 'u'
	ws = exprnd(1, c, pts);
else
	warning('finance:portrand:unknownMethod', ...
		'Unknown METHOD (''%s'') specified. Will use default.',method);
	ws = exprnd(1, c, pts);
end
ws = repmat((1 ./ sum(ws)), c, 1) .* ws;
ws = ws';

% Compute means and standard deviations of portfolio returns

y = sqrt(portvar(asset, ws));		% Standard deviations for each weight vector
z = portror(ret, ws);				% Rate of return for each weight vector
[z, in] = sort(z);					% Sort output for plotting
y = y(in);							% Standard deviations in same order as returns

if nargout == 0
	plot(y, z, 'c.', 'linewidth', 3.5, 'Tag', 'portrandplot');
else
	risk = y;
	ror = z';
	weights = ws;
end
